﻿/* ***********************************************
 * 
 * Author		:  飞无痕
 * Email		:  wsptr@sohu.com
 * DateTime		:  2012-1-30 17:22
 * Description	:  与游戏手柄相关的API函数
 *
 * ***********************************************/

using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;

namespace Walson.Multimedia
{
    /// <summary>
    /// 游戏手柄的相关API
    /// </summary>
    public static class JoystickAPI
    {
        #region 错误号定义
        /// <summary>
        /// 没有错误
        /// </summary>
        public const int JOYERR_NOERROR = 0;
        /// <summary>
        /// 参数错误
        /// </summary>
        public const int JOYERR_PARMS = 165;
        /// <summary>
        /// 无法正常工作
        /// </summary>
        public const int JOYERR_NOCANDO = 166;
        /// <summary>
        /// 操纵杆未连接 
        /// </summary>
        public const int JOYERR_UNPLUGGED = 167;
        #endregion

        #region 游戏手柄的参数信息
        /// <summary>
        /// 游戏手柄的参数信息
        /// </summary>
        [StructLayout(LayoutKind.Sequential)]
        public struct JOYCAPS
        {
            /// <summary>
            /// 
            /// </summary>
            public ushort wMid;
            /// <summary>
            /// 
            /// </summary>
            public ushort wPid;
            /// <summary>
            /// 
            /// </summary>
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]
            public string szPname;
            /// <summary>
            /// 
            /// </summary>
            public int wXmin;
            /// <summary>
            /// 
            /// </summary>
            public int wXmax;
            /// <summary>
            /// 
            /// </summary>
            public int wYmin;
            /// <summary>
            /// 
            /// </summary>
            public int wYmax;
            /// <summary>
            /// 
            /// </summary>
            public int wZmin;
            /// <summary>
            /// 
            /// </summary>
            public int wZmax;
            /// <summary>
            /// 
            /// </summary>
            public int wNumButtons;
            /// <summary>
            /// 
            /// </summary>
            public int wPeriodMin;
            /// <summary>
            /// 
            /// </summary>
            public int wPeriodMax;
            /// <summary>
            /// 
            /// </summary>
            public int wRmin;
            /// <summary>
            /// 
            /// </summary>
            public int wRmax;
            /// <summary>
            /// 
            /// </summary>
            public int wUmin;
            /// <summary>
            /// 
            /// </summary>
            public int wUmax;
            /// <summary>
            /// 
            /// </summary>
            public int wVmin;
            /// <summary>
            /// 
            /// </summary>
            public int wVmax;
            /// <summary>
            /// 
            /// </summary>
            public int wCaps;
            /// <summary>
            /// 
            /// </summary>
            public int wMaxAxes;
            /// <summary>
            /// 
            /// </summary>
            public int wNumAxes;
            /// <summary>
            /// 
            /// </summary>
            public int wMaxButtons;
            /// <summary>
            /// 
            /// </summary>
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]
            public string szRegKey;
            /// <summary>
            /// 
            /// </summary>
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)]
            public string szOEMVxD;
        }
        #endregion

        #region 游戏手柄的位置与按钮状态
        /// <summary>
        /// 游戏手柄的位置与按钮状态
        /// </summary>        
        [StructLayout(LayoutKind.Sequential)]
        public struct JOYINFO
        {
            /// <summary>
            /// X
            /// </summary>
            public int wXpos;
            /// <summary>
            /// Y
            /// </summary>
            public int wYpos;
            /// <summary>
            /// Z
            /// </summary>
            public int wZpos;
            /// <summary>
            /// 按钮
            /// </summary>
            public int wButtons;
        }

        /// <summary>
        /// 游戏手柄的位置与按钮状态
        /// </summary>
        [StructLayout(LayoutKind.Sequential)]
        public struct JOYINFOEX
        {
            /// <summary>
            /// Size, in bytes, of this structure.
            /// </summary>
            public int dwSize;
            /// <summary>
            /// Flags indicating the valid information returned in this structure. Members that do not contain valid information are set to zero.
            /// </summary>
            public int dwFlags;
            /// <summary>
            /// Current X-coordinate.
            /// </summary>
            public int dwXpos;
            /// <summary>
            /// Current Y-coordinate.
            /// </summary>
            public int dwYpos;
            /// <summary>
            /// Current Z-coordinate.
            /// </summary>
            public int dwZpos;
            /// <summary>
            /// Current position of the rudder or fourth joystick axis.
            /// </summary>
            public int dwRpos;
            /// <summary>
            /// Current fifth axis position.
            /// </summary>
            public int dwUpos;
            /// <summary>
            /// Current sixth axis position.
            /// </summary>
            public int dwVpos;
            /// <summary>
            /// Current state of the 32 joystick buttons. The value of this member can be set to any combination of JOY_BUTTONn flags, where n is a value in the range of 1 through 32 corresponding to the button that is pressed.
            /// </summary>
            public int dwButtons;
            /// <summary>
            /// Current button number that is pressed.
            /// </summary>
            public int dwButtonNumber;
            /// <summary>
            /// Current position of the point-of-view control. Values for this member are in the range 0 through 35,900. These values represent the angle, in degrees, of each view multiplied by 100. 
            /// </summary>
            public int dwPOV;
            /// <summary>
            /// Reserved; do not use.
            /// </summary>
            public int dwReserved1;
            /// <summary>
            /// Reserved; do not use.
            /// </summary>
            public int dwReserved2;

            /// <summary>
            /// 转字符串
            /// </summary>
            /// <returns></returns>
            public new string ToString()
            {
                return string.Format("Button Number:{0}\t\tButtons:{1}\t\tFlags:{2}\r\n" +
                     "POV:{3}\t\tRpos:{4}\t\tSize:{5}\r\n" +
                     "Upos:{6}\t\tVpos:{7}\t\tXpos\t\tYpos:{8}\t\tZpos:{9}\r\n",
                     dwButtonNumber, dwButtons, dwFlags, dwPOV, dwRpos, dwSize, dwUpos, dwVpos, dwXpos, dwYpos, dwZpos);
            }

            /// <summary>
            /// 不等于
            /// </summary>
            /// <param name="info1">待比较参数1</param>
            /// <param name="info2">待比较参数2</param>
            /// <returns>比较结果</returns>
            static public bool operator !=(JOYINFOEX info1, JOYINFOEX info2)
            {
                long a, b;
                a = info1.dwButtonNumber + info1.dwButtons + info1.dwFlags + info1.dwPOV + info1.dwReserved1 + info1.dwReserved2 + info1.dwRpos + info1.dwSize + info1.dwUpos + info1.dwVpos + info1.dwXpos + info1.dwYpos + info1.dwZpos;
                b = info2.dwButtonNumber + info2.dwButtons + info2.dwFlags + info2.dwPOV + info2.dwReserved1 + info2.dwReserved2 + info2.dwRpos + info2.dwSize + info2.dwUpos + info2.dwVpos + info2.dwXpos + info2.dwYpos + info2.dwZpos;
                return a != b;
            }

            /// <summary>
            /// 等于
            /// </summary>
            /// <param name="info1">待比较参数1</param>
            /// <param name="info2">待比较参数2</param>
            /// <returns>比较结果</returns>
            static public bool operator ==(JOYINFOEX info1, JOYINFOEX info2)
            {
                long a, b;
                a = info1.dwButtonNumber + info1.dwButtons + info1.dwFlags + info1.dwPOV + info1.dwReserved1 + info1.dwReserved2 + info1.dwRpos + info1.dwSize + info1.dwUpos + info1.dwVpos + info1.dwXpos + info1.dwYpos + info1.dwZpos;
                b = info2.dwButtonNumber + info2.dwButtons + info2.dwFlags + info2.dwPOV + info2.dwReserved1 + info2.dwReserved2 + info2.dwRpos + info2.dwSize + info2.dwUpos + info2.dwVpos + info2.dwXpos + info2.dwYpos + info2.dwZpos;
                return a == b;
            }
        }
        #endregion

        #region JOYINFOEX.dwFlags值的定义
        /// <summary>
        /// 返回值 X
        /// </summary>
        public const long JOY_RETURNX = 0x1;
        /// <summary>
        /// 返回值 Y
        /// </summary>
        public const long JOY_RETURNY = 0x2;
        /// <summary>
        /// 返回值 Z
        /// </summary>
        public const long JOY_RETURNZ = 0x4;
        /// <summary>
        /// 返回值 NR
        /// </summary>
        public const long JOY_RETURNR = 0x8;
        /// <summary>
        /// 返回值 NU
        /// </summary>
        public const long JOY_RETURNU = 0x10;
        /// <summary>
        /// 返回值 NV
        /// </summary>
        public const long JOY_RETURNV = 0x20;
        /// <summary>
        /// 返回值 POV
        /// </summary>
        public const long JOY_RETURNPOV = 0x40;
        /// <summary>
        /// 返回值 按键
        /// </summary>
        public const long JOY_RETURNBUTTONS = 0x80;
        /// <summary>
        /// 返回值 原始数据
        /// </summary>
        public const long JOY_RETURNRAWDATA = 0x100;
        /// <summary>
        /// 返回值 POVCTS
        /// </summary>
        public const long JOY_RETURNPOVCTS = 0x200;
        /// <summary>
        /// 返回值 已回中
        /// </summary>
        public const long JOY_RETURNCENTERED = 0x400;
        /// <summary>
        /// 
        /// </summary>
        public const long JOY_USEDEADZONE = 0x800;
        /// <summary>
        /// 
        /// </summary>
        public const long JOY_RETURNALL = (JOY_RETURNX | JOY_RETURNY | JOY_RETURNZ | JOY_RETURNR | JOY_RETURNU | JOY_RETURNV | JOY_RETURNPOV | JOY_RETURNBUTTONS);
        /// <summary>
        /// 
        /// </summary>
        public const long JOY_CAL_READALWAYS = 0x10000;
        /// <summary>
        /// 
        /// </summary>
        public const long JOY_CAL_READRONLY = 0x2000000;
        /// <summary>
        /// 
        /// </summary>
        public const long JOY_CAL_READ3 = 0x40000;
        /// <summary>
        /// 
        /// </summary>
        public const long JOY_CAL_READ4 = 0x80000;
        /// <summary>
        /// 
        /// </summary>
        public const long JOY_CAL_READXONLY = 0x100000;
        /// <summary>
        /// 
        /// </summary>
        public const long JOY_CAL_READYONLY = 0x200000;
        /// <summary>
        /// 
        /// </summary>
        public const long JOY_CAL_READ5 = 0x400000;
        /// <summary>
        /// 
        /// </summary>
        public const long JOY_CAL_READ6 = 0x800000;
        /// <summary>
        /// 
        /// </summary>
        public const long JOY_CAL_READZONLY = 0x1000000;
        /// <summary>
        /// 
        /// </summary>
        public const long JOY_CAL_READUONLY = 0x4000000;
        /// <summary>
        /// 
        /// </summary>
        public const long JOY_CAL_READVONLY = 0x8000000;
        #endregion

        /// <summary>
        /// 检查系统是否配置了游戏端口和驱动程序。如果返回值为零，表明不支持操纵杆功能。如果返回值不为零，则说明系统支持游戏操纵杆功能。
        /// </summary>
        /// <returns></returns>
        [DllImport("winmm.dll")]
        public static extern int joyGetNumDevs();

        /// <summary>
        /// 获取某个游戏手柄的参数信息
        /// </summary>
        /// <param name="uJoyID">指定游戏杆(0-15)，它可以是JOYSTICKID1或JOYSTICKID2</param>
        /// <param name="pjc"></param>
        /// <param name="cbjc">JOYCAPS结构的大小</param>
        /// <returns></returns>
        [DllImport("winmm.dll")]
        public static extern int joyGetDevCaps(int uJoyID, ref JOYCAPS pjc, int cbjc);

        /// <summary>
        /// 获取操纵杆位置和按钮状态
        /// </summary>
        /// <param name="uJoyID"></param>
        /// <param name="pji"></param>
        /// <returns></returns>
        [DllImport("winmm.dll")]
        public static extern int joyGetPos(int uJoyID, ref JOYINFO pji);

        /// <summary>
        /// 获取操纵杆位置和按钮状态
        /// </summary>
        /// <param name="uJoyID"></param>
        /// <param name="pji"></param>
        /// <returns></returns>
        [DllImport("winmm.dll")]
        public static extern int joyGetPosEx(int uJoyID, ref JOYINFOEX pji);
    }
}
